home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / PROGRAMM / CC_C / 0151.ZIP / INDEX.C < prev    next >
C/C++ Source or Header  |  1985-08-15  |  15KB  |  551 lines

  1. /********************************************************
  2. *                            *
  3. *            INDEX                *
  4. *           Text file index generator.        *
  5. *                            *
  6. *          T. Jennings 7/21/81            *
  7. *        MSDOS version 13 Nov. 82        *
  8. *        Repaired 30 Aug 84            *
  9. *                            *
  10. *********************************************************
  11.  
  12.     INDEX Generates an ASCII WordStar (or equiv.) compatible
  13.     index from a text file. Words to be indexed are marked
  14.     with a control character. Entire phrases can be indexed
  15.     as well, by marking both ends with a different character.
  16.  
  17.     The index generated will be sorted alphabetically, with
  18.     the first character of all entries in caps. Each entry
  19.     will contain the page number as well.
  20.  
  21.     Two control characters, ^K and ^P are used. ^K marks
  22.     single words, and ^P marks phrases. Phrases too long
  23.     will be truncated to fit.
  24.  
  25. Examples: 
  26.     The sixth word in this ^Ksentence will be put in the index.
  27.  
  28.     ^PThis entire phrase^P will be indexed.
  29.  
  30.     The index for these two items, once printed, would look
  31.     like:
  32.  
  33.     Sentence .................................... 2
  34.     This entire phrase .......................... 3
  35.  
  36. See INDEX.DOC for details
  37. */
  38.  
  39. #include <stdio.h>
  40. #include <ctype.h>
  41.  
  42. char *getmem();
  43. long sizmem();
  44. long _xseek();
  45. char *strip_path();
  46. char *next_arg();
  47.  
  48. #define MAXENTRIES 10000
  49.  
  50. #define FALSE 0
  51. #define TRUE 1
  52. #define ERROR -1
  53. #define WORD_MARK 0x0b            /* The single word marker */
  54. #define    PHRASE_MARK 0x10        /* Phrase marker */
  55. #define CONTROLZ 0x1a
  56. #define CR 0x0d                /* useful ASCII characters */
  57. #define LF 0x0a
  58. #define FF 0x0c
  59. #define WORD_LEN 39            /* maximum word or phrase size */
  60. #define LAST_COL 40            /* column to start page # */
  61. #define PAGE_LEN 66            /* default lines per page */
  62. #define DEF_LMARGIN 8            /* default left margin, */
  63. #define DEF_RMARGIN 72            /* ... and right margin */
  64. #define DEF_TMARGIN 1            /* default top of page margin */
  65. #define DEF_BMARGIN 8
  66.  
  67. int char_count;                /* # characters looked at in file, */
  68. int word_count;                /* # words looked at */
  69. int line_count;                /* ditto lines */
  70. int this_line;                /* current line #/page */
  71. int entries;                /* # entries in index */
  72. int this_page;                /* current page */
  73. int page_size;                /* current max page length */
  74. int lmargin,rmargin;            /* current left and right margins */
  75. int top_margin;                /* lines from top of page */
  76. int bot_margin;
  77. int found_index;            /* true if old index found */
  78. int line_num;                /* true if line numbers in index */
  79.  
  80. int tofc;                /* generate table of contents */
  81.  
  82. int inbuf;                /* text file */
  83. char inname[80];            /* where we save ASCII filenames */
  84.  
  85. char *pile;                /* ptr to text buffer, */
  86. char *topofpile;            /* the top of the pile */
  87. long memsize;                /* how big it is */
  88. long currsize;                /* current size */
  89. char *pointers[MAXENTRIES];        /* pile pointers for sorting */
  90. char pl;                /* current index to */
  91.  
  92. /* System interface for INDEX. Make sure theres at least one argument (the
  93. filename). Open it for reading, (error check) make a temporary file for
  94. output (filename.$I$) (error check). Then...
  95.  
  96. 1/    Read the file sequentially, looking for marked words,     [ index()  ]
  97. 2/    Cleanup the pile of entries (remove leading blanks, convert each
  98.     1st character to uper case)                [ cleanup() ]
  99. 3/    Sort the pile alphabeticlly                [ sort()   ]
  100. 4/    Dump the pile to the disk, expanding each to correct width,
  101.     and removing duplicate entries                [ dump()  ]
  102. 5/    Return to CP/M
  103.  */
  104. main(argc,argv)
  105. int argc;
  106. char *argv[];
  107. {
  108. char *s,*p,sw[80],arg[80];
  109. int i;
  110.  
  111.     printf("INDEX -- Document Index Generator (c) Fido Software 1981, 1982, 1983, 1984, 1985\r\n");
  112.     page_size= PAGE_LEN;
  113.     lmargin= DEF_LMARGIN;
  114.     rmargin= DEF_RMARGIN;
  115.     top_margin= DEF_TMARGIN;
  116.     bot_margin= DEF_BMARGIN;
  117.     found_index= FALSE;
  118.     line_num= FALSE;
  119.     tofc= FALSE;
  120.  
  121. /* Try to allocate a bunch of memory. If theres not enough, say so. */
  122.  
  123.     allmem();            /* find largest area to allocate */
  124.     memsize= sizmem();
  125.     if (memsize < 4096L) {        /* stop if not enough */
  126.         printf("Oh no, not enough memory! Less than");
  127.         printf("4096 bytes to work in!\r\n");
  128.         exit(1);
  129.     }
  130.     pile= getmem(memsize);
  131.     topofpile= pile;
  132.     *pile= '\0';
  133.     currsize= 0L;
  134.     *inname= '\0';
  135.  
  136. /* Process the command line. We must have a filename, and optionally one
  137. of two options: list amount of memory, of add line numbers to the index. */
  138.  
  139.     for (i= 1; i < argc; i++) {        /* Process any options, */
  140.         p= argv[i];
  141.         cpyarg(arg,p);            /* possible name */
  142.         if (strlen(inname) == 0) strcpy(inname,arg);
  143.         strip_switch(sw,p);        /* process switches, */
  144.         s= sw;
  145.         while (*s) {
  146.             switch(tolower(*s)) {
  147.                 case 'L':
  148.                     printf("Putting line numbers in the index.\r\n");
  149.                     line_num= TRUE;
  150.                     break;
  151.  
  152.                 case '?':
  153.                     printf("INDEX has %lu bytes to work in.\r\n",memsize);
  154.                     break;
  155.  
  156.                 case 'T':
  157.                     printf("Table of Contents (TOFC.INS)\r\n");
  158.                     tofc= 1;
  159.                     break;
  160.             }
  161.             ++s;
  162.         }
  163.     }
  164.     if (strlen(inname) == 0) {
  165.         printf("Specify a file to make an index for\r\n");
  166.         exit(1);
  167.     }
  168.     inbuf= _xopen(inname,2);    /*try to open source file,*/
  169.     if (inbuf == ERROR) {
  170.         printf("Can't find %s\r\n",inname);
  171.         exit(1);
  172.     }
  173.  
  174.     printf("Adding a new index to '%s'.\r\n",inname);
  175.     printf("1) Scanning,\r\n");
  176.     index();        /* scan the file, */
  177.     cleanup();        /* convert each 1st char to upper case */
  178.     printf ("2) Sorting,\r\n");
  179.     sort();            /* sort it, */
  180.     printf ("3) Saving it,\r\n");
  181.     dump();            /* write it to the disk, */
  182.     printf ("4) Cleaning up.\r\n");
  183.  
  184.     _xclose(inbuf);
  185.     printf ("done.\r\n");
  186.     printf("Put %d words in the index ",entries);
  187.     printf("out of a total of %d words.\r\n",word_count);
  188.     exit(0);            /* exit. */
  189. }
  190. /* Read the input file, and make a list of words to index. Maintain
  191. the global variables indicating word count, etc. Leave a pile of
  192. strings, followed by the page #, terminated with a control-z. 
  193.  
  194. When done, PILE[] will have sequential null terminated strings, terminated
  195. by a single control-z. Each pointer in POINTERS[] will point to the start
  196. of each string, with the last pointing to the control-z.
  197. */
  198. index() {
  199.  
  200. int inword;            /* blank or character flag */
  201. int gotword;            /* true if saving this word */
  202. int gotphrase;            /* true if saving this phrase */
  203. int entry_len;            /* size of word or phrase */
  204. char linebuf[132];        /* character line buffer */
  205. int i,j;
  206. int last_char_blank;        /* suppress mult. spaces 'tween lines */
  207. char c;
  208.  
  209.     inword= FALSE;        /* no word yet, */
  210.     gotword= FALSE;        /* no marked word found, */
  211.     gotphrase= FALSE;    /* no marked phrase found, */
  212.     last_char_blank= FALSE;    /* too early... */
  213.  
  214.     pl= 0;            /* current index */
  215.     char_count= 0;
  216.     word_count= 0;        /* and our booleans */
  217.     line_count= 0;
  218.     entries= 0;
  219.     this_page= 1;
  220.     this_line= top_margin;    /* wordstars current margin */
  221.  
  222.     while ( !found_index && (fill_line(linebuf) != CONTROLZ)) {
  223.  
  224.         if (scan_line(linebuf) == TRUE)        /* look for dot cmds */
  225.             continue;            /* get next line */
  226.  
  227.         if (this_line >= (page_size - bot_margin)) {
  228.             this_line= top_margin;
  229.             ++this_page;
  230.         }
  231.  
  232.         if ((pl + 1) >= MAXENTRIES) {
  233.             printf("(Too many entries, ");
  234.             break;
  235.         }
  236.  
  237.         if (pile < topofpile > (memsize - 200L)) {
  238.             printf("Memory buffer full, ");
  239.             break;
  240.         }
  241.  
  242.         j= 0;
  243.         ++line_count;                /* count total lines,*/
  244.         while ((c= linebuf[j++]) != '\0') {    /* while not end/line*/
  245.             ++char_count;
  246.             if (c == ' ') {
  247.                 inword= FALSE;        /* end of a word */
  248.                 if (gotword) {        /* if we were looking*/
  249.                     ++pile;        /* leave null to mark*/
  250.                     if (line_num)
  251.                         sprintf(pile,"%d-%d",this_page,this_line);
  252.                     else sprintf(pile,"%d",this_page);
  253.                     while (*pile++);/* point to next */
  254.                      ++entries;    /* count another */
  255.                     gotword= FALSE;    /* done with word */
  256.                 }
  257.  
  258.             } else if (inword == FALSE) {    /* non-white char */
  259.                 inword= TRUE;
  260.                 ++word_count;
  261.             }
  262.  
  263.             if (c == WORD_MARK) {    /* new word to save */
  264.                 gotword= TRUE;    /* start saving next char */
  265.                 entry_len= 0;
  266.                 pointers[pl++]= pile;/* set the pointer */
  267.  
  268.             } else if (c == PHRASE_MARK) {
  269.                 if (gotphrase) {    /* if we had one before, */
  270.                     ++pile;    /* let the last null mark it */
  271.                     if (line_num)
  272.                         sprintf(pile,"%d-%d",this_page,this_line);
  273.                     else sprintf(pile,"%d",this_page);
  274.                     while (*pile++);
  275.                     ++entries; /* counter another */
  276.                     gotphrase= FALSE;
  277.  
  278.                 } else { /* new phrase */
  279.                     gotphrase= TRUE; /* else start now. */
  280.                     entry_len= 0;    /* just starting */
  281.                     pointers[pl++]= pile;/* point to it */
  282.                 }
  283.             }
  284.  
  285.             /* see if we should store a character */
  286.  
  287.             else if (  (gotphrase || gotword) &&
  288.                    (entry_len++ < WORD_LEN) &&
  289.                    ((c != '.') || gotphrase) &&
  290.                    !(last_char_blank && c == ' ') &&
  291.                    isprint(c) ) {
  292.                 *pile++= c;    /* were saving now */
  293.                 *pile= '\0';    /* null terminate it always, */
  294.                 last_char_blank= (c ==' ' ? TRUE : FALSE);
  295.             }
  296.         }
  297.         ++this_line;
  298.     }
  299.     *pile= CONTROLZ;            /* mark the top of the pile, */
  300.     pointers[pl]= pile;            /* set its pointer */
  301. }
  302. /* Sort routine, straight out of K + R, page 108. */
  303.  
  304. sort() {
  305.  
  306. int i,j,gap;
  307. char *temp;
  308.  
  309.     for (gap= pl / 2; gap > 0; gap /= 2) {
  310.         for (i= gap; i < pl; i++) {
  311.             for (j= i - gap; j >= 0; j-= gap) {
  312.                 if (comp(pointers[j],pointers[j + gap],4) <= 0)
  313.                     break;
  314.                 temp= pointers[j];
  315.                 pointers[j]= pointers[j + gap];
  316.                 pointers[j + gap]= temp;
  317.             }
  318.         }
  319.     }
  320. }
  321.  
  322. /* Quick compare. Does masking instead of tolower(), etc. Only compares
  323. the first 4 characters. */
  324.  
  325. comp(s1,s2,len)
  326. char *s1,*s2;
  327. int len;
  328. {
  329. int i,v;
  330.  
  331.     for (;i--;) {
  332.         if (!*s1) return(0);        /* return if end of string */
  333.         if (!*s2) return(0);
  334.         v= (*s1++ & 0x5f) - (*s2++ & 0x5f);
  335.         if (v) break;
  336.     }
  337.     return(v);
  338. }
  339. /* Dump the pile to the disk. Convert each entry to a single line, making each
  340. an even number of columns wide. Put the page number at the end. Look for
  341. duplicate entries, and remove them. */
  342.  
  343. dump() {
  344. int column;
  345. int i,x;
  346. char *current_entry;
  347. char *j;
  348. char c;
  349. char last_alpha;
  350. int local_i;
  351.  
  352.     column= 0;
  353.     i= 0;
  354.     if (found_index == FALSE) {            /* dont duplicate this */
  355.         sendstr("\r\n..index\r\n");
  356.     }
  357.     last_alpha= '\0';                /* section header flag */
  358.  
  359.     while (*pointers[i] != CONTROLZ) {
  360.         j =pointers[i++];            /* send chars until null */
  361.         if (*j !=0xff) {            /* if its a deleted dup copy, */
  362.                             /* skip this */
  363.  
  364.             if (last_alpha != *j) {        /* if different alpha */
  365.                 last_alpha= *j;        /* group, do a CR LF */
  366.                 sendstr("\r\n");
  367.             }
  368.  
  369.             current_entry =j;        /* else save a copy, */
  370.             for (x= lmargin; x > 0; x--)    /* tab to left margin */
  371.                 wrtc(' ',inbuf);
  372.  
  373.             while (c =*j++) {
  374.                 wrtc (c,inbuf);
  375.                 ++column;
  376.             }
  377.             while (column++ < LAST_COL)    /* make an entry */
  378.                 wrtc ('.',inbuf);    /* tab over, */
  379.  
  380.             wrtc (' ',inbuf);        /* type the page # */
  381.             while (c =*j++)
  382.                 wrtc (c,inbuf);
  383.  
  384. /* Look for duplicate entries; if we find one, remove it (mark 0xff) and 
  385. output it's page # on the current one. If more than 5, stop, and start the
  386. rest on the next line. */
  387.  
  388.             local_i =0;
  389.             if (*pointers[i] !=CONTROLZ) {
  390.                 while ((comp(current_entry,pointers[i+local_i]) ==0) && (local_i < 6) ) {
  391.                     j =pointers[i+local_i++];
  392.                     *j =0xff;    /* mark it removed */
  393.                     while (*j++);    /* skip the entry, */
  394.                     wrtc (',',inbuf);/* type a comma, */
  395.                     while (c =*j++)    /* send the page # */
  396.                         wrtc (c,inbuf);
  397.                 }
  398.             }
  399.             wrtc (CR,inbuf);        /* new line, */
  400.             wrtc (LF,inbuf);
  401.             column =0;            /* next line */
  402.         }
  403.     }
  404.     wrtc (CONTROLZ,inbuf);
  405. }
  406. /* Fill a line buffer with characters. Convert all white_space characters
  407. to a single blank, put a null at the end.  */
  408.  
  409. fill_line(buffer)
  410. char buffer[];
  411. {
  412. int i,n;
  413. char c;
  414. int inblank;                /* true to suppress blanks */
  415. long pos;
  416.  
  417.     inblank= FALSE;
  418.     i= 0;
  419.  
  420.     while (i < 132) {
  421.         n= _xread(inbuf,&c,1);
  422.         if (n == 0) return(CONTROLZ);    /* check physical end */
  423.  
  424.         c&= 0x7f;            /* strip it */
  425.  
  426.         if (c == LF) return(c);        /* stop if LF */
  427.         if (c == CONTROLZ) {        /* dont send the control-z */
  428.             _xseek(inbuf,-1L,1);    /* back up over it, */
  429.             return (c);
  430.         }
  431.         if (incset(c," ,\t\r;!")) c= ' '; /* white space is space only */
  432.  
  433.         if ((c != ' ') || (inblank == FALSE)) {
  434.             buffer[i++]= c;
  435.             buffer[i]= '\0';
  436.         }
  437.         inblank= (c == ' ' ? TRUE : FALSE);
  438.     } 
  439.     return(c);
  440. }
  441. /* Return true if the character is in the string. */
  442.  
  443. incset(c,s)
  444. char c,*s;
  445. {
  446.     while (*s) {
  447.         if (c == *s++) return(1);
  448.     }
  449.     return(0);
  450. }
  451.  
  452. /* Scan for dot commands. When and if we find a dot command, fool the 
  453. caller into thinking that the line we were passed is now empty. (Return TRUE)
  454. If we find the index mark, "..index", set the flag so we dont duplicate
  455. it at dump time. If we find a formfeed, treat it the same as a .pa. */
  456.  
  457. scan_line(buffer)
  458. char *buffer;
  459. {
  460. int i;
  461. char c,*p,tc[80];
  462.  
  463.     if (*buffer =='.') {        /* as per WS specs, must be first atom */
  464.         if (comp (buffer,".pa",3) ==0) {
  465.             ++this_page;
  466.             this_line= top_margin;
  467.  
  468.         } else if (comp(buffer,".sh",3) == 0) {
  469.             p= next_arg(buffer);
  470.             strcpy(tc,p);
  471.             printf("%s\r\n",tc);
  472.  
  473.         } else if (comp (buffer,"..index",7) ==0) {
  474.             found_index =TRUE;
  475.  
  476.         } else if (comp (buffer,".pn",3) == 0) {
  477.             i= get_next_num(buffer);    /* get new page num, */
  478.             if (i)                /* if not zero, */
  479.                 this_page= i;        /* set it, */
  480.  
  481.         } else if (comp (buffer,".pl",3) == 0) {
  482.             i= get_next_num(buffer);    /* get new paper */
  483.             if (i > 5)            /* length, */
  484.                 page_size= i;
  485.  
  486.         } else if (comp (buffer,".mt",3) == 0) {
  487.             i= get_next_num(buffer);
  488.             if (i == 0)
  489.                 i= 1;
  490.             if (i < 40)            /* get top margin, */
  491.                 top_margin= i;        /* set if reasonable */
  492.  
  493.         } else if (comp (buffer,".mb",3) == 0) {
  494.             i= get_next_num(buffer);
  495.             if (i < page_size)
  496.                 bot_margin= i;
  497.         }
  498.         return (TRUE);
  499.     }
  500.  
  501.     if (*buffer == FF) {
  502.         ++this_page;
  503.         this_line= top_margin;
  504.         return(TRUE);
  505.     }
  506.     return (FALSE);
  507. }
  508. /* Clean up the pile by converting each first character to upper
  509. case. Deletes leading blanks by adjusting the pointer, but only if
  510. the string is more than 1 char long. */
  511.  
  512. cleanup()
  513. {
  514. int i;
  515. char c;
  516.     i =0;
  517.     while ((c= toupper(*pointers[i])) !=CONTROLZ)
  518.     {    if ((*pointers[i] ==' ') && (*pointers[i+1] !='\0'))
  519.         {    ++(pointers[i]);
  520.             c =toupper(*pointers[i]);
  521.         }
  522.         *pointers[i++] =c;
  523.     }
  524. }
  525. /* Send an ascii string to the output file */
  526.  
  527. sendstr(string)
  528. char *string;
  529. {
  530.     _xwrite(inbuf,string,strlen(string));
  531. }
  532. /* Write a character to the file. */
  533.  
  534. wrtc(c,file)
  535. char c;
  536. int file;
  537. {
  538.     _xwrite(file,&c,1);
  539. }
  540. /* Find the next number in the string, return it's value, or 0 
  541. if none found. */
  542.  
  543. get_next_num(string)
  544. char *string;
  545. {
  546. int i;
  547.     while (! isdigit(*string))
  548.         ++string;        /* skip leading text, */
  549.     return(atoi(string));
  550. }
  551.